<template>
    <div style="width:100%;height:100%">
        <button @click="HighPerformance">HighPerformance</button>
        <button @click="RemovePerformance">RemovePerformance</button>
        <div id="3d-graph" class="graph-3d" style="height:900px"></div>
    </div>
</template>

<script>
import ForceGraph3D from "3d-force-graph";
import {
    CSS2DRenderer,
    CSS2DObject
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js";
import SpriteText from "three-spritetext";
import RES from "./metaData.js";
export default {
    data() {
        return {
            Graph: null,
            highlightNodes: null,
            highlightLinks: null,
            hoverNode: null,
            nodes: [],
            links: [],
            maxSize: 1,
            subNodes: [],
            subLinks: [],
            bloomPass: null
        };
    },
    mounted() {
        this.Graph = ForceGraph3D({
            extraRenderers: [new CSS2DRenderer()]
        })(document.getElementById("3d-graph"))
            .height(900) //画布高度
            .backgroundColor("rgba(0,0,0,0)") //画布背景色
            .showNavInfo(false) //禁用页脚
            .onNodeClick(node => {
                // Aim at node from outside it
                const distance = 100;
                const distRatio =
                    1 + distance / Math.hypot(node.x, node.y, node.z);

                const newPos =
                    node.x || node.y || node.z
                        ? {
                              x: node.x * distRatio,
                              y: node.y * distRatio,
                              z: node.z * distRatio
                          }
                        : { x: 0, y: 0, z: distance }; // special case if node is in (0,0,0)
                this.Graph.cameraPosition(
                    newPos, // new position
                    node, // lookAt ({ x, y, z })
                    3000 // ms transition duration
                );
            })
            .nodeResolution(16);
        // .cameraPosition(
        //     {
        //         x: -60,
        //         y: -120,
        //         z: -60
        //     }, // new position
        //     {
        //         x: 0,
        //         y: 0,
        //         z: 0
        //     }, // lookAt ({ x, y, z })
        //     3000 // ms transition duration
        // ); //修改初始相机位置

        this.nodes = RES.nodes;
        this.links = RES.links;

        //    加入数据
        this.Graph.graphData({
            nodes: [...this.nodes, ...this.subNodes],
            links: [...this.links, ...this.subLinks]
        });
        this.node();
        this.linkArrow();
        // // 添加动画
        // this.linkText();
        // fit to canvas when engine stops
        // this.Graph.onEngineStop(() => this.Graph.zoomToFit(200));
        // this.HighPerformance();
    },
    methods: {
        // HighPerformance
        HighPerformance() {
            if (this.bloomPass) return;
            // 添加阴影
            this.bloomPass = new UnrealBloomPass();
            this.bloomPass.strength = 2.5;
            this.bloomPass.radius = 1;
            this.bloomPass.threshold = 0;
            this.Graph.postProcessingComposer().addPass(this.bloomPass);
        },
        RemovePerformance() {
            this.bloomPass &&
                this.Graph.postProcessingComposer().removePass(this.bloomPass);
            this.bloomPass = null;
        },
        // 渲染节点
        node() {
            let _this = this;
            this.Graph.nodeThreeObject(node => {
                const nodeEl = document.createElement("div");
                nodeEl.textContent = node.userData.name;
                nodeEl.style.color = "rgba(255, 255, 255)";
                nodeEl.className = "node-label";
                return new CSS2DObject(nodeEl);
            })
                .nodeThreeObjectExtend(true)
                .nodeOpacity(1)
                .nodeColor(node => {
                    return node.colors[node?.userData?.status || 0];
                })
                // 节点文字
                .linkThreeObjectExtend(true);
        },
        // 线和线上文字
        linkText() {
            this.Graph.linkThreeObjectExtend(true)
                .linkThreeObject(link => {
                    const sprite = new SpriteText(`${link.type}`);
                    sprite.color = "rgba(255, 255, 255)";
                    sprite.textHeight = 1.5;
                    return sprite;
                })
                .linkPositionUpdate((sprite, { start, end }) => {
                    const middlePos = Object.assign(
                        ...["x", "y", "z"].map(c => ({
                            [c]: start[c] + (end[c] - start[c]) / 2 // calc middle point
                        }))
                    );
                    // Position sprite
                    Object.assign(sprite.position, middlePos);
                })
                // 曲线
                .linkCurvature(0.5)
                // 线颜色
                .linkColor(link => {
                    let obj = [...this.nodes, ...this.subNodes].find(item => {
                        return item.id == link.end;
                    });
                    return obj.colors[obj?.userData?.status || 0];
                })
                // 线宽度
                .linkWidth(link => 0.3)
                // .linkWidth(link => (this.highlightLinks.has(link) ? 1 : 0.3))
                .linkOpacity(0.7)
                .linkDirectionalParticles(5);
        },
        // 箭头
        linkArrow() {
            this.Graph.linkDirectionalArrowLength(2)
                .linkDirectionalArrowRelPos(1)
                .linkDirectionalParticleSpeed(0.005);
        }
    }
};
</script>

<style lang="less">
.graph-3d {
    width: 100%;
    height: 100%;
    background-color: rgb(7, 18, 56);
}
</style>
